package world3d.sound;

import javax.sound.sampled.*;
import javax.sound.sampled.DataLine.Info;
import java.io.File;
import java.io.IOException;

import static javax.sound.sampled.AudioFormat.Encoding.PCM_SIGNED;
import static javax.sound.sampled.AudioSystem.getAudioInputStream;

public class SoundManager {
	public static void tryToPlay(Sounds sound) {
		try {
			play(sound);
		} catch (IOException | UnsupportedAudioFileException | LineUnavailableException e) {
			e.printStackTrace();
		}
	}
	public static void play(Sounds sound) throws IOException, UnsupportedAudioFileException, LineUnavailableException {
		final File file = new File(SoundManager.class.getResource(sound.getSoundPath()).getPath());

		try (final AudioInputStream in = getAudioInputStream(file)) {

			final AudioFormat outFormat = getOutFormat(in.getFormat());
			final Info info = new Info(SourceDataLine.class, outFormat);


			try (final SourceDataLine line =
						 (SourceDataLine) AudioSystem.getLine(info)) {


				if (line != null) {
					line.open(outFormat);
					setVolume(line, 20);
					line.start();
					stream(getAudioInputStream(outFormat, in), line);
					line.drain();
					line.stop();

				}
			}

		} catch (UnsupportedAudioFileException
				| LineUnavailableException
				| IOException e) {
			throw new IllegalStateException(e);
		}
	}
	private static void setVolume(SourceDataLine source, int volume) {

		try {

			FloatControl gainControl = (FloatControl) source.getControl(FloatControl.Type.MASTER_GAIN);
			BooleanControl muteControl = (BooleanControl) source.getControl(BooleanControl.Type.MUTE);

			if (volume == 0) {
				muteControl.setValue(true);
			} else {
				muteControl.setValue(false);
				gainControl.setValue((float) (Math.log(volume / 100d) / Math.log(10.0) * 20.0));
			}
		}

		catch (Exception e) {
			e.printStackTrace();
//			LOGGER.log(Level.WARNING, "unable to set the volume to the provided source", e);
		}
	}
	private static AudioFormat getOutFormat(AudioFormat inFormat) {
		final int ch = inFormat.getChannels();
		final float rate = inFormat.getSampleRate();
		return new AudioFormat(PCM_SIGNED, rate, 16, ch, ch * 2, rate, false);
	}

	private static void stream(AudioInputStream in, SourceDataLine line)
			throws IOException {
		final byte[] buffer = new byte[4096];
		for (int n = 0; n != -1; n = in.read(buffer, 0, buffer.length)) {
			line.write(buffer, 0, n);
		}
	}
}
